/*=============================================================================
FILE: CTextParser.cpp

Text parser.
=============================================================================*/

#include "CTextParser.h"
#include "CMathFixed.h"


CTextParser::CTextParser()
{
}


CTextParser::~CTextParser()
{
}

int CTextParser::GetNumLines() const
{
	return m_numLines;
}


const AECHAR *CTextParser::GetTextPtrForLine( int line ) const
{
	const AECHAR *pOut = NULL;

	if( m_pwszContent )
	{
		pOut = m_pwszContent + GetIndexForLine( line );
	}

	return pOut;
}


int CTextParser::GetIndexForLine( int line ) const
{
	int32 out = 0;

	if( line < m_numLines )
	{
		out = m_lineInfoVector[line];
		out >>= 16;
        out &= 0xFFFF;
	}

	return out;
}


int CTextParser::GetNumCharsForLine( int line ) const
{
	int32 out = 0;

	if( line < m_numLines )
	{
		out = m_lineInfoVector[line];
		out &= 0xFFFF;
	}

	return out;
}


void CTextParser::Parse(const CGraphicFont *pFont,const AECHAR *pwszContent,int width)
{
	eRC rc = RC_SUCCESS;

	m_pFont = pFont;
	m_pwszContent = pwszContent;
	m_width = width;
	m_numLines = 0;

	// parse if necessary
	if( m_pFont != NULL && m_pwszContent != NULL && m_width > 0 )
	{		
		int idx = 0;
		int newLines = 0;
		int charsFit = 0;
		//boolean truncate = FALSE;
		int numChars = WSTRLEN( m_pwszContent );

		// parse
		BLOCK_START( block )
		{
			while ( idx < numChars ) 
			{
				eFontTextTokenType token = GetTokenType( m_pwszContent[idx] );

				// render any text
				if( token == FONT_TEXT_TOKEN_NEWLINE )
				{
					// newline
					// to avoid rendering trailing newlines, don't increment
					// the line count until we draw something else
					newLines++;
					idx++;
				}
				else if( token == FONT_TEXT_TOKEN_NULL )
				{
					// we're done -- bail
					BLOCK_CHECK( block, FALSE );
				}
				else
				{
					// add any newlines
					while ( newLines > 0 )
					{
						m_lineInfoVector[m_numLines] = ( ( ( idx & 0xFF ) << 16 ) | ( 0 ) );
						BLOCK_CHECKRC( block, rc );

						m_numLines++;
						newLines--;
					}

					// measure what we can fit on this line
					// make sure we can fit at least one character
					m_pFont->MeasureTextWidth( m_pwszContent + idx, numChars - idx, m_width, &charsFit );
					charsFit = ParseLine( idx, charsFit );
					BLOCK_CHECK( block, ( charsFit > 0 ) );

					// save the start of the line and the number of chars
					m_lineInfoVector[m_numLines] = ( ( ( idx & 0xFFFF ) << 16 ) | ( charsFit & 0xFFFF ) );
					BLOCK_CHECKRC( block, rc );

					// advance
					idx += charsFit;
					m_numLines++;
					
					// skip trailing newline or space
					token = GetTokenType( m_pwszContent[idx] );

					if( token == FONT_TEXT_TOKEN_NEWLINE || token == FONT_TEXT_TOKEN_SPACE )
					{
						idx++;
					}
				}
			}
		}
		BLOCK_END( block );
	}
}


int CTextParser::ParseLine( int idx, int charsFit )
{
	// SANITY CHECK
	ASSERT( m_pFont != NULL );
	ASSERT( m_pwszContent != NULL );

	// we want to draw either:
	// 1) everything we can up to the first special token
	// 2) everything we can up to the last space
	// 3) everything we can fit up to the end of the text
	boolean firstToken = TRUE;
	int pos = idx + charsFit;
	while( pos > idx )
	{
		eFontTextTokenType token = GetTokenType( m_pwszContent[pos] );

		switch( token )
		{
		case FONT_TEXT_TOKEN_NULL:
		case FONT_TEXT_TOKEN_NEWLINE:
			charsFit = pos - idx;
			firstToken = FALSE;
			break;
		
		case FONT_TEXT_TOKEN_SPACE:
			if( firstToken )
			{
				charsFit = pos - idx;
			}
			firstToken = FALSE;
			break;

		default:
			// do nothing
			break;
		};

		// keep going
		pos--;
	}

	return charsFit;
}

eFontTextTokenType CTextParser::GetTokenType( AECHAR c )
{
	eFontTextTokenType token = FONT_TEXT_TOKEN_NONE;
	
	switch( c )
	{
		case (AECHAR) ' ':
			token = FONT_TEXT_TOKEN_SPACE;
			break;
			
		case (AECHAR) '\t':
			token = FONT_TEXT_TOKEN_TAB;
			break;
			
		case (AECHAR) '\n':
			token = FONT_TEXT_TOKEN_NEWLINE;
			break;
			
		case (AECHAR) '\0':
			token = FONT_TEXT_TOKEN_NULL;
			break;
			
		default:
			break;
	}
	
	return token;
}